package com.open.tool.dispatch.impl;

import com.open.common.utils.DateUtils;
import com.open.tool.dispatch.IServerLogDispatch;
import com.open.tool.model.ServerLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author dashu03
 * @date 2025年06月07日 17:26
 * @description
 */

@Slf4j
@Component
public class ServerLogDispatchImpl implements IServerLogDispatch {

    private static final int BUFFER_SIZE = 8192; // 缓冲区大小(8KB)
    private static final long MULTI_THREAD_THRESHOLD = 10 * 1024 * 1024; // 10MB阈值
    private static final String SERVER_LOG_PATH = "logs/open-sys.log";

    @Override
    public byte[] downloadLog() {
        try {
            File logDir = new File("logs");
            if (!logDir.exists() || !logDir.isDirectory()) {
                throw new FileNotFoundException("日志目录不存在: logs/");
            }

            File[] logFiles = logDir.listFiles((dir, name) -> name.endsWith(".log"));
            if (logFiles == null || logFiles.length == 0) {
                log.warn("日志目录中没有找到 .log 文件");
                return new byte[0];
            }

            // 使用 ByteArrayOutputStream 缓冲 ZIP 输出
            try (ByteArrayOutputStream zipBuffer = new ByteArrayOutputStream();
                 ZipOutputStream zipOut = new ZipOutputStream(zipBuffer)) {

                byte[] buffer = new byte[BUFFER_SIZE];

                for (File file : logFiles) {
                    try (InputStream fis = Files.newInputStream(file.toPath())) {
                        // 创建 ZIP 条目
                        ZipEntry zipEntry = new ZipEntry(file.getName());
                        zipOut.putNextEntry(zipEntry);

                        int length;
                        while ((length = fis.read(buffer)) > 0) {
                            zipOut.write(buffer, 0, length);
                        }
                        zipOut.closeEntry();
                    }
                }

                zipOut.finish();
                return zipBuffer.toByteArray();
            }
        } catch (IOException e) {
            log.error("打包日志文件失败:", e);
            return new byte[0];
        }
    }



    @Override
    public boolean deleteLog() {
        File logFile = new File(SERVER_LOG_PATH);

        if (!logFile.exists()) {
            log.warn("尝试删除日志文件失败：文件不存在 - {}", SERVER_LOG_PATH);
            return false;
        }

        if (!logFile.canWrite()) {
            log.error("尝试删除日志文件失败：无写入权限 - {}", SERVER_LOG_PATH);
            return false;
        }

        try {
            boolean deleted = logFile.delete();
            if (deleted) {
                log.info("成功删除日志文件: {}", SERVER_LOG_PATH);
            } else {
                log.warn("日志文件删除失败（可能被其他进程占用）: {}", SERVER_LOG_PATH);
            }
            return deleted;
        } catch (SecurityException e) {
            log.error("删除日志文件失败：安全限制", e);
            return false;
        }
    }

    @Override
    public boolean clearLog() {
        File logFile = new File(SERVER_LOG_PATH);
        File parentDir = logFile.getParentFile();

        if (!logFile.exists()) {
            log.warn("尝试清空日志文件失败：文件不存在 - {}", SERVER_LOG_PATH);
            return false;
        }

        if (!logFile.canWrite()) {
            log.error("尝试清空日志文件失败：无写入权限 - {}", SERVER_LOG_PATH);
            return false;
        }

        try {
            // 使用 FileOutputStream 打开文件并立即关闭，达到清空目的
            try (FileOutputStream fos = new FileOutputStream(logFile)) {
                // 写入 0 字节，清空内容
            }

            // 2. 删除归档日志文件（例如 logs/open-sys-1.log、logs/open-sys-2.log 等）
            if (parentDir != null && parentDir.exists()) {
                File[] archivedLogs = parentDir.listFiles((dir, name) ->
                        name.startsWith("open-sys-") && name.endsWith(".log"));

                if (archivedLogs != null) {
                    for (File archivedLog : archivedLogs) {
                        //log.info("已删除归档日志文件: {}", archivedLog.getName());
                        if (!archivedLog.delete()) {
                            log.warn("无法删除归档日志文件: {}", archivedLog.getName());
                        }
                    }
                }
            }

            //log.info("成功清空日志文件内容: {}", SERVER_LOG_PATH);
            return true;
        } catch (IOException e) {
            log.error("清空日志文件失败:", e);
            return false;
        }
    }


    @Override
    public ServerLog getServerLog() {
        ServerLog serverLog = new ServerLog();
        File logFile = new File(SERVER_LOG_PATH);

        try {
            serverLog.setCurrentTime(DateUtils.getCurrentTimes());

            // 获取文件大小并转换为MB
            long fileSizeBytes = logFile.length();
            BigDecimal fileSize = new BigDecimal(fileSizeBytes)
                    .divide(new BigDecimal(1024 * 1024), 2, RoundingMode.HALF_UP);
            serverLog.setLogFileSize(fileSize);

            // 根据文件大小决定使用单线程还是多线程处理
            if (fileSizeBytes <= MULTI_THREAD_THRESHOLD) {
                // 小文件使用单线程处理
                processFileSingleThread(logFile, serverLog);
            } else {
                // 大文件使用多线程处理
                processFileMultiThread(logFile, serverLog);
            }

        } catch (Exception e) {
            log.error("读取日志文件失败:", e);
        }
        return serverLog;
    }

    // 单线程处理文件
    private void processFileSingleThread(File logFile, ServerLog serverLog) throws IOException {
        int warnCount = 0;
        int errorCount = 0;
        int totalCount = 0;
        // 使用 ArrayDeque（固定大小，自动移除最旧数据）
        Deque<String> logLines = new ArrayDeque<>(500);

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                        Files.newInputStream(logFile.toPath()), StandardCharsets.UTF_8), ServerLogDispatchImpl.BUFFER_SIZE)) {
            String line;
            while ((line = reader.readLine()) != null) {
                totalCount++;
                if (line.contains("WARN")) warnCount++;
                else if (line.contains("ERROR")) errorCount++;

                if (logLines.size() >= 500) {
                    logLines.removeFirst(); // 移除最旧的行
                }
                logLines.addLast(line); // 添加最新的行
            }
        }

        serverLog.setWarnSize(warnCount);
        serverLog.setErrorSize(errorCount);
        serverLog.setLogSize(totalCount);
        serverLog.setLogData(new ArrayList<>(logLines));
    }

    // todo 多线程处理文件
    private void processFileMultiThread(File logFile, ServerLog serverLog){

    }

}
